%% copy riak-0.14.2 source to learn dynamo implementation and erlang
%% author: lichuang
%% copy source from riak_core_ring_events.erl
-module(edynamo_ring_events).

-behaviour(gen_event).

%% API
-export([start_link/0,
         add_handler/2,
         add_sup_handler/2,
         add_callback/1,
         add_sup_callback/1,
         ring_update/1,
         force_update/0,
         ring_sync_update/1,
         force_sync_update/0]).

%% gen_event callbacks
-export([init/1, handle_event/2, handle_call/2,
         handle_info/2, terminate/2, code_change/3]).

-record(state, {callback}).

%% ===================================================================
%% API functions
%% ===================================================================
start_link() ->
  gen_event:start({local, ?MODULE}).

add_handler(Handler, Args) ->
  gen_event:add_handler(?MODULE, Handler, Args).

add_sup_handler(Handler, Args) ->
  gen_event:add_sup_handler(?MODULE, Handler, Args).

add_callback(Fn) when is_function(Fn) ->
  gen_event:add_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).

add_sup_callback(Fn) when is_function(Fn) ->
  gen_event:add_sup_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).

force_update() ->
  {ok, Ring} = edynamo_ring_manager:get_my_ring(),
  ring_update(Ring).

ring_update(Ring) ->
  gen_event:notify(?MODULE, {ring_update, Ring}).

force_sync_update() ->
  {ok, Ring} = edynamo_ring_manager:get_my_ring(),
  ring_sync_update(Ring).

ring_sync_update(Ring) ->
  gen_event:sync_notify(?MODULE, {ring_update, Ring}).
%% ===================================================================
%% gen_event callbacks
%% ===================================================================
init([Fn]) ->
  {ok, Ring} = edynamo_ring_manager:get_my_ring(),
  Fn(Ring),
  {ok, #state{callback = Fn}}.

handle_event({ring_update, Ring}, State) ->
  (State#state.callback)(Ring),
  {ok, State};

handle_event(_Event, State) ->
  {ok, State}.

handle_call(_Request, State) ->
  {ok, ok, State}.

handle_info(_Info, State) ->
  {ok, State}.

terminate(_Reason, _State) ->
  ok.

code_change(_OldVsn, State, _Extra) ->
  {ok, State}.
